1 module unde.games.dizzy.omega.dog;
2 
3 import derelict.opengl3.gl;
4 
5 import std.algorithm;
6 import std.conv;
7 import std.math;
8 import std.stdio;
9 import unde.games.dizzy.omega.main;
10 import unde.games.dizzy.omega.rope;
11 import unde.games.object;
12 import unde.games.renderer;
13 import unde.games.collision_detector;
14 import unde.games.object;
15 import unde.global_state;
16 
17 class Dog:StaticGameObject
18 {
19     static int num;
20     int number;
21 
22     int hidden;
23     
24     enum SPEED = 0.1;
25     enum MAX_V = 0.3;
26     enum A = 0.01;
27     enum STATE
28     {
29         WATCH,
30         GO_UP,
31         GO_RIGHT,
32         CLOSE_MOUTH,
33         GO_LEFT,
34         GO_DOWN,
35         OPEN_MOUTH,
36         FLY_AWAY,
37     }
38 
39     STATE state;
40 
41     float def_x, def_y, def_z;
42     float dx = 0.0, dy = 0.0;
43     long frame;
44     long start_anim;
45     int mouth;
46 
47     Rope rope;
48 
49     LiveGameObject the_hero;
50 
51     bool search_surface;
52     static GLuint rope_texture;
53     
54     this(MainGameObject root, float[3] coords, float[3] rope_start, float by, uint length, float segl, LiveGameObject hero)
55     {
56         def_x = x = coords[0];
57         def_y = y = coords[1];
58         def_z = z = coords[2];
59         the_hero = hero;
60         number = num++;
61         models["dog"] = root.models["dog"];
62         //collision_objects["solid"] = root.collision_objects["solid"];
63 
64         rope = new Rope(root, rope_start, [x-1.4, y, z], by, length, segl);
65         
66         super(root);
67     }
68 
69     void cut_rope()
70     {
71         rope.cut(2);
72     }
73 
74     bool fly_anim(GlobalState gs, string name)
75     {
76         float f = (frame*4)%240;
77         float degree = 0.0;
78         float translate = 0.0;
79         
80         if (f < 120.0)
81             translate = 0.2 - 0.4*f/120.0;
82         else if (f < 240.0)
83             translate = -0.2 + 0.4*(f - 120.0)/120.0;
84 
85         if (f < 120.0)
86             degree = f/2 - 30.0;
87         else if (f < 240.0)
88             degree = 30.0 - (f/2 - 60.0);
89 
90         glTranslatef(0.0, translate, 0.0);
91         
92         if (name == "Dog-LeftWing")
93         {
94             glTranslatef(0.0, 0.4, 0.5);
95             glRotatef(degree, 1.0, 0.0, 0.0);
96             glTranslatef(0.0, -0.4, -0.5);
97         }
98         
99         if (name == "Dog-RightWing")
100         {
101             glTranslatef(0.0, 0.4, -0.5);
102             glRotatef(-degree, 1.0, 0.0, 0.0);
103             glTranslatef(0.0, -0.4, 0.5);
104         }
105         
106         if (name.startsWith("Dog-Head"))
107         {
108             if ((name[8] - '1') != mouth)
109             {
110                 return false;
111             }
112         }
113 
114         return true;
115     }
116 
117     void hide()
118     {
119         hidden++;
120     }
121 
122     override void draw(GlobalState gs)
123     {
124         if ( abs(root.scrx-x) > 16.0 &&
125              abs(root.scrx-def_x) > 16.0 ||
126              abs(root.scry-y) > 9.0 )
127             return;
128 
129         if (!hidden)
130         {
131             glPushMatrix();
132             glTranslatef(x, y, z);
133             if (dx > 0.0) glRotatef(180,0,1,0);
134             recursive_render(gs, models["dog"], &fly_anim);
135             glPopMatrix();
136             
137             rope.draw(gs);
138         }
139         else if (hidden == 1)
140         {
141             rope.draw_part(gs, 0, rope.cut_segm);
142         }
143     }
144 
145     immutable float side_sensor_dx = 1.0;
146     immutable float[2] side_sensor_y = [0.5, 0.8];
147     
148     immutable float bottom_sensor_dx = 0.6;
149     immutable float bottom_sensor_dy = 0.5;
150 
151     override bool tick(GlobalState gs)
152     {
153         if ( hidden || abs(root.scrx-x) > 16.0 &&
154              abs(root.scrx-def_x) > 16.0 ||
155              abs(root.scry-y) > 9.0 )
156             return true;
157 
158         float speedfactor = 1.0;
159         
160         if (state != STATE.FLY_AWAY)
161         {
162             if (the_hero.x < x)
163             {
164                 speedfactor = 0.5;
165             }
166             else if (the_hero.x < x+1.5)
167             {
168                 speedfactor = the_hero.x - x;
169             }
170             else
171                 speedfactor = 2.0;
172         }
173         
174         frame++;
175         x += dx * speedfactor;
176         y += dy * speedfactor;
177 
178         final switch (state)
179         {
180             case STATE.WATCH:
181                 float dhy = the_hero.y + 1.0 - y;
182                 if (dhy > 0.0 && dy < dhy/2.0 && dy < MAX_V)
183                     dy += A;
184                 else if (dhy < 0.0 && dy > dhy/2.0 && dy > -MAX_V)
185                     dy -= A;
186                 else dy = 0.0;
187         
188                 if (the_hero.x + 4.5 > x)
189                     the_hero.x = x - 4.5;
190 
191                 if (abs(the_hero.x - x) < 7.0)
192                 {
193                     long f = frame%200;
194                     if (f < 10)
195                         mouth = 1;
196                     else if (f < 20)
197                         mouth = 0;
198                     else if (f < 30)
199                         mouth = 1;
200                     else if (f < 40)
201                         mouth = 2;
202                     else if (f < 50)
203                         mouth = 1;
204                     else if (f < 60)
205                         mouth = 0;
206                     else if (f < 70)
207                         mouth = 1;
208                     else
209                         mouth = 2;
210                 }
211                 else mouth = 2;
212 
213                 DizzyOmega dz = cast(DizzyOmega) root;
214                 if (dz.dizzy_throw_branch_quest_state == 2)
215                 {
216                     mouth = 2;
217                     dx = 0.000001;
218                     dy = SPEED;
219                     state = STATE.GO_UP;
220                 }
221                 
222                 if (rope.cut_segm >= 0)
223                 {
224                     dx = -SPEED*1.5;
225                     dy = SPEED*1.5/10;
226                     z = -2.0;
227                     state = STATE.FLY_AWAY;
228                 }
229                 
230                 break;
231                 
232             case STATE.GO_UP:
233                 if (y > 0.9)
234                 {
235                     state = STATE.GO_RIGHT;
236                     dy = 0;
237                     dx = SPEED;
238                 }
239                 break;
240                 
241             case STATE.GO_RIGHT:
242                 if (x > 364.5)
243                 {
244                     state = STATE.CLOSE_MOUTH;
245                     start_anim = frame;
246                     dy = 0;
247                     dx = 0.00001;
248                 }
249                 else if (x > 364.2)
250                 {
251                     mouth = 0;
252                 }
253                 else if (x > 364.0)
254                 {
255                     mouth = 1;
256                 }
257 
258                 break;
259 
260             case STATE.CLOSE_MOUTH:
261                 long f = frame - start_anim;
262                 if (f < 10)
263                 {
264                     mouth = 1;
265                     dx = -SPEED;
266                     dy = 0;
267                     state = STATE.GO_LEFT;
268                 }
269                 break;
270                 
271             case STATE.GO_LEFT:
272                 if (x <= def_x)
273                 {
274                     state = STATE.GO_DOWN;
275                     dx = 0;
276                     dy = -SPEED;
277                 }
278                 break;
279 
280             case STATE.GO_DOWN:
281                 if (y <= def_y)
282                 {
283                     state = STATE.OPEN_MOUTH;
284                     start_anim = frame;
285                     dx = 0;
286                     dy = 0;
287                 }
288                 break;
289 
290             case STATE.OPEN_MOUTH:
291                 long f = frame - start_anim;
292                 if (f < 20)
293                 {
294                     mouth = 0;
295                 }
296                 else if (f < 30)
297                 {
298                     mouth = 1;
299                 }
300                 else if (f < 40)
301                 {
302                     mouth = 2;
303                     if (rope.cut_segm < 0)
304                         state = STATE.WATCH;
305                     else
306                     {
307                         dx = -SPEED*1.5;
308                         dy = SPEED*1.5/10;
309                         z = -2.0;
310                         state = STATE.FLY_AWAY;
311                     }
312                 }
313                 break;
314             case STATE.FLY_AWAY:
315                 if (x < 270.0)
316                 {
317                     state = STATE.WATCH;
318                     hide();
319                 }
320         }
321 
322         if (rope.rope.length > 1)
323         {
324             float f = (frame*4)%240;
325             float translate = 0.0;
326             
327             if (f < 120.0)
328                 translate = 0.2 - 0.4*f/120.0;
329             else if (f < 240.0)
330                 translate = -0.2 + 0.4*(f - 120.0)/120.0;
331 
332             rope.rope[$-1] = [x-1.4, y+translate, z];
333             rope.tick(gs);
334         }
335 
336         return true;
337     }    
338 
339     override void load(string[string] s)
340     {
341         string p = "dog"~number.to!(string);
342         if (p~"-x" in s)
343             x = s[p~"-x"].to!(float);
344         else
345             x = def_x;
346             
347         if (p~"-y" in s)
348             y = s[p~"-y"].to!(float);
349         else
350             y = def_y;
351             
352         if (p~"-z" in s)
353             z = s[p~"-z"].to!(float);
354         else
355             z = def_z;
356 
357         if (p~"-dx" in s)
358             dx = s[p~"-dx"].to!(float);
359         else
360             dx = 0.0;
361 
362         if (p~"-dy" in s)
363             dy = s[p~"-dy"].to!(float);
364         else
365             dy = 0.0;
366 
367         if (p~"-state" in s)
368             state = s[p~"-state"].to!(STATE);
369         else
370             state = STATE.WATCH;
371 
372         if (p in s)
373         {
374             hidden = (s[p] == "hidden-rope")?2:(s[p] == "hidden")?1:0;
375         }
376         else
377         {
378             hidden = 0;
379         }
380 
381         rope.rope[$-1] = [x-1.4, y, z];
382         rope.load(s);
383     }
384 
385     override void save(ref string[string] s)
386     {
387         string p = "dog"~number.to!(string);
388         if (hidden == 1)
389             s[p] = "hidden";
390         else if (hidden == 2)
391             s[p] = "hidden-rope";
392 
393         s[p~"-x"] = x.to!(string);
394         s[p~"-y"] = y.to!(string);
395         s[p~"-z"] = z.to!(string);
396         s[p~"-dx"] = dx.to!(string);
397         s[p~"-dy"] = dy.to!(string);
398         s[p~"-state"] = state.to!(string);
399 
400         rope.save(s);
401     }    
402 }
403